#ifndef SIMPLE_GEOM_BOOL_ALGEBRA_EXTRA_HPP
#define SIMPLE_GEOM_BOOL_ALGEBRA_EXTRA_HPP

#include "bool_algebra.hpp"
#include "algorithm.hpp"

namespace simple::geom
{
	// TODO: disable the element wise * and + for this (or bool vector in general) to not make inclusion of this header silently change behavior

	template <
		typename C, typename C2,
		size_t D, size_t D2,
		typename O, typename O2
	>
	[[nodiscard]]
	constexpr auto operator*
	(
		disjunction<C,D,O> one,     // A1xA2x...An
		disjunction<C2,D2,O2> other // B1xB2x...Bm
	)
	noexcept
	{
		// A1xA2x...Anx1
		const auto row = vector(one.range);

		// 1xB1xB2x...Bm
		const auto column = deeply_transformed(other.range,
			[](auto x) { return vector(x); });

		// A1xA2x...AnxB1xB2...xBm
		return to_disjunction(row(column));
	}

	class conjunctive_bool
	{
		bool raw;
		public:

		constexpr conjunctive_bool() : raw(conjunct::identity) {}
		constexpr explicit conjunctive_bool(bool raw) : raw(raw) {}
		constexpr explicit operator bool() const noexcept { return raw; }
		constexpr conjunctive_bool& operator+=(conjunctive_bool other) noexcept
		{
			raw = conjunct{}(raw, other.raw);
			return *this;
		}
		constexpr conjunctive_bool operator*(conjunctive_bool other) const noexcept
		{
			other.raw = disjunct{}(other.raw, raw);
			return other;
		}
	};

	// same as disjunction *, but additionally converting to conjunction_bool and back to customize identity and ops used by vector application (matrix multiplication)
	template <
		typename C, typename C2,
		size_t D, size_t D2,
		typename O, typename O2
	>
	[[nodiscard]]
	constexpr auto operator+
	(
		conjunction<C,D,O> one,
		conjunction<C2,D2,O2> other
	)
	noexcept
	{
		const auto row = vector(deeply_transformed(one.range,
			[](auto x) { return conjunctive_bool(x); }));
		const auto column = deeply_transformed(other.range,
			[](auto x) { return vector(conjunctive_bool(x)); });
		return to_conjunction(deeply_transformed(row(column),
			[](auto x) { return bool(x); }));
	}

	// TODO: figure these out
	// ideally want elementwise when possible
	// but there are lot of strange cases

	template <
		typename C, typename C2,
		size_t D, size_t D2,
		typename O, typename O2
	>
	constexpr auto operator+
	(
		disjunction<C,D,O>,
		disjunction<C2,D2,O2>
	)
	= delete;

	template <
		typename C, typename C2,
		size_t D, size_t D2,
		typename O, typename O2
	>
	constexpr auto operator+
	(
		disjunction<C,D,O>,
		conjunction<C2,D2,O2>
	)
	= delete;

	template <
		typename C, typename C2,
		size_t D, size_t D2,
		typename O, typename O2
	>
	constexpr auto operator+
	(
		conjunction<C,D,O>,
		disjunction<C2,D2,O2>
	)
	= delete;

	template <
		typename C, typename C2,
		size_t D, size_t D2,
		typename O, typename O2
	>
	constexpr auto operator*
	(
		conjunction<C,D,O>,
		conjunction<C2,D2,O2>
	)
	= delete;

	template <
		typename C, typename C2,
		size_t D, size_t D2,
		typename O, typename O2
	>
	constexpr auto operator*
	(
		conjunction<C,D,O> one,
		disjunction<C2,D2,O2>
	)
	= delete;

	template <
		typename C, typename C2,
		size_t D, size_t D2,
		typename O, typename O2
	>
	constexpr auto operator*
	(
		disjunction<C,D,O> one,
		conjunction<C2,D2,O2>
	)
	= delete;


} // namespace simple::geom

#endif /* end of include guard */
